/*
 * @Author: Swance
 * @Date: 2023-12-20
 * @Description: 选择插件
 */

import { fabric } from 'fabric';
import { IEditor } from '@/types/global';
import { BoardSyncEvent } from '@/utils/Const.ts';

class SelectPlugin {
  canvas: fabric.Canvas;
  editor: IEditor;
  selectMode: boolean;
  moveMode: boolean;
  selectedObjects: any[];
  static pluginName: string = 'SelectPlugin';
  static apis: string[] = ['setSelectMode', 'getActiveObject'];

  constructor(canvas: fabric.Canvas, editor: IEditor) {
    this.canvas = canvas;
    this.editor = editor;
    this.selectMode = false;
    this.moveMode = false;
    this.selectedObjects = [];
    this.init();
  }

  init() {
    const { canvas } = this;
    canvas.on('selection:created', (e) => {
      if (!this.selectMode) return;
      this.editor.emit('selected', {
        selected: e.selected,
      });
      this.editor.emit('selecting', { isSelected: true });
    });

    canvas.on('selection:updated', (e) => {
      if (!this.selectMode) return;
      this.editor.emit('updateSelect', {
        selected: e.selected,
      });
      this.editor.emit('selecting', { isSelected: true });
    });

    canvas.on('selection:cleared', (e) => {
      if (!this.selectMode) return;
      this.editor.emit('deselected');
      this.editor.emit('selecting', { isSelected: false });
    });

    // 元素移动时，移动栏不显示
    canvas.on('object:moving', () => {
      if (!this.selectMode) return;
      this.moveMode = true;
      this.editor.emit('selecting', { isSelected: false });
    });

    // 在选择模式下，判断鼠标左键按下时即锁定一个元素，需同步至服务器
    canvas.on('mouse:down', (e) => {
      if (!this.selectMode) return;
      if (!e.target || !(e.button === 1)) return;
      let lockIds: string | string[];
      if (e.target.type === 'activeSelection') {
        lockIds = e.target
          .getObjects()
          .map((element: fabric.Object) => element.id);
      } else {
        lockIds = e.target.id;
      }
      // 把正在操作的（需要上锁）元素ID发给服务器
      this.editor.sendMessage({
        type: BoardSyncEvent.OPERATE_ELEMENTS,
        data: JSON.stringify(lockIds),
      });
    });
    // 在选择模式下，判断鼠标左键松开时即解锁一个元素，需同步至服务器
    // 元素结束移动后，移动栏显示
    canvas.on('mouse:up', (e) => {
      if (!this.selectMode) return;
      if (this.moveMode) {
        this.moveMode = false;
        this.editor.emit('selecting', { isSelected: true });
      }
      if (!e.target || !(e.button === 1)) return;
      let unlockIds: string | string[];
      if (e.target.type === 'activeSelection') {
        unlockIds = e.target
          .getObjects()
          .map((element: fabric.Object) => element.id);
      } else {
        unlockIds = e.target.id;
      }
      // 把没有操作的（需要解锁）元素ID发给服务器
      this.editor.sendMessage({
        type: BoardSyncEvent.NOT_OPERATE_ELEMENTS,
        data: JSON.stringify(unlockIds),
      });
    });

    // 元素放大缩小时，不显示移动栏
    canvas.on('object:scaling', () => {
      if (!this.selectMode) return;
      this.editor.emit('selecting', { isSelected: false });
    });

    // 元素旋转时，不显示移动栏
    canvas.on('object:rotating', () => {
      if (!this.selectMode) return;
      this.editor.emit('selecting', { isSelected: false });
    });

    // 元素修改完后，显示移动栏
    canvas.on('object:modified', () => {
      if (!this.selectMode) return;
      this.editor.emit('selecting', { isSelected: true });
    });
  }

  setSelectMode(params: boolean) {
    this.selectMode = params;
    if (this.selectMode) {
      this.canvas.discardActiveObject();
      this.canvas.selection = true;
    } else {
      this.editor.emit('selecting', { isSelected: false });
    }
  }

  getActiveObject() {
    const activeObject = this.canvas.getActiveObject();
    if (!activeObject) return;
    const { height, width, aCoords, type } = activeObject;
    const zoomX =
      type === 'activeSelection' ? activeObject.scaleX : activeObject.zoomX;
    const zoomY =
      type === 'activeSelection' ? activeObject.scaleY : activeObject.zoomY;
    const minTop = Math.min(
      aCoords?.tl.y,
      aCoords?.bl.y,
      aCoords?.br.y,
      aCoords?.tr.y,
    );
    const minLeft = Math.min(
      aCoords?.tl.x,
      aCoords?.bl.x,
      aCoords?.br.x,
      aCoords?.tr.x,
    );
    const barTop = minTop + height * zoomY - height * zoomY - 70;
    const barLeft = Math.round(((width as number) * zoomX) / 2 + minLeft);
    return {
      type: activeObject.type,
      top: barTop,
      left: barLeft,
      activeObject,
    };
  }
}
export default SelectPlugin;
